<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Canvas Image Filter Demo</title>
    <style>
        canvas {
            display: block;
            margin: 20px auto;
            border: 1px solid black;
        }

        .buttons {
            text-align: center;
        }

        button {
            margin: 5px;
            padding: 10px;
        }
    </style>
</head>

<body>

    <canvas id="imageCanvas" width="500" height="500"></canvas>
    <div class="buttons">
        <button onclick="applyFilter('original')">原图</button>
        <button onclick="applyFilter('grayscale')">黑白</button>
        <button onclick="applyFilter('invert')">反转</button>
        <button onclick="applyFilter('brightness')">曝光</button>
        <button onclick="applyFilter('mosaic')">马赛克</button>
    </div>

    <script>
        const canvas = document.getElementById('imageCanvas');
        const ctx = canvas.getContext('2d');
        const img = new Image();

        // 加载图片并绘制到 canvas 上
        img.src = './img/test.jpg'; // 图片URL
        img.onload = () => {
            ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
        };

        // 获取图片的像素数据
        function getImageData() {
            return ctx.getImageData(0, 0, canvas.width, canvas.height);
        }

        // 应用滤镜
        function applyFilter(filter) {
            // 获取原始像素数据
            let imageData = getImageData();
            let data = imageData.data;

            switch (filter) {
                case 'grayscale':
                    for (let i = 0; i < data.length; i += 4) {
                        let avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
                        data[i] = avg;     // R
                        data[i + 1] = avg; // G
                        data[i + 2] = avg; // B
                    }
                    break;
                case 'invert':
                    for (let i = 0; i < data.length; i += 4) {
                        data[i] = 255 - data[i];       // R
                        data[i + 1] = 255 - data[i + 1]; // G
                        data[i + 2] = 255 - data[i + 2]; // B
                    }
                    break;
                case 'brightness':
                    const brightness = 50; // 增加亮度值
                    for (let i = 0; i < data.length; i += 4) {
                        data[i] += brightness;     // R
                        data[i + 1] += brightness; // G
                        data[i + 2] += brightness; // B
                    }
                    break;
                case 'mosaic':
                    const blockSize = 10; // 定义马赛克块的大小
                    for (let y = 0; y < canvas.height; y += blockSize) {
                        for (let x = 0; x < canvas.width; x += blockSize) {
                            // 计算每个块的起始像素的索引
                            let i = (y * canvas.width + x) * 4;
                            // 获取该块的颜色（选取块的左上角像素颜色）
                            let red = data[i];
                            let green = data[i + 1];
                            let blue = data[i + 2];

                            // 将该块的所有像素设置为相同颜色
                            for (let dy = 0; dy < blockSize; dy++) {
                                for (let dx = 0; dx < blockSize; dx++) {
                                    let ni = ((y + dy) * canvas.width + (x + dx)) * 4;
                                    if (ni < data.length) {
                                        data[ni] = red;
                                        data[ni + 1] = green;
                                        data[ni + 2] = blue;
                                    }
                                }
                            }
                        }
                    }
                    break;
                case 'original':
                    ctx.drawImage(img, 0, 0, canvas.width, canvas.height); // 还原原图
                    return;
            }

            // 把处理后的像素数据放回到 canvas
            ctx.putImageData(imageData, 0, 0);
        }
    </script>

</body>

</html>